"---------------------------------------------------------------------------
" vimrc functions:
"

function! vimrc#sticky_func() abort
  let sticky_table = {
        \',' : '<', '.' : '>', '/' : '?',
        \'1' : '!', '2' : '@', '3' : '#', '4' : '$', '5' : '%',
        \'6' : '^', '7' : '&', '8' : '*', '9' : '(', '0' : ')',
        \ '-' : '_', '=' : '+',
        \';' : ':', '[' : '{', ']' : '}', '`' : '~', "'" : "\"", '\' : '|',
        \}
  let special_table = {
        \"\<ESC>" : "\<ESC>", "\<Space>" : ';', "\<CR>" : ";\<CR>"
        \}

  let char = ''

  while 1
    let char = nr2char(getchar())

    if char =~ '\l'
      let char = toupper(char)
      break
    elseif has_key(sticky_table, char)
      let char = sticky_table[char]
      break
    elseif has_key(special_table, char)
      let char = special_table[char]
      break
    endif
  endwhile

  return char
endfunction

function! vimrc#add_numbers(num) abort
  let prev_line = getline('.')[: col('.')-1]
  let next_line = getline('.')[col('.') :]
  let prev_num = matchstr(prev_line, '\d\+$')
  if prev_num != ''
    let next_num = matchstr(next_line, '^\d\+')
    let new_line = prev_line[: -len(prev_num)-1] .
          \ printf('%0'.len(prev_num . next_num).'d',
          \    max([0, substitute(prev_num . next_num, '^0\+', '', '')
          \         + a:num])) . next_line[len(next_num):]
  else
    let new_line = prev_line . substitute(next_line, '\d\+',
          \ "\\=printf('%0'.len(submatch(0)).'d',
          \         max([0, substitute(submatch(0), '^0\+', '', '')
          \              + a:num]))", '')
  endif

  if getline('.') !=# new_line
    call setline('.', new_line)
  endif
endfunction

function! vimrc#toggle_option(option_name) abort
  execute 'setlocal' a:option_name.'!'
  execute 'setlocal' a:option_name.'?'
endfunction

function! vimrc#on_filetype() abort
  if execute('filetype') =~# 'OFF'
    " Lazy loading
    silent! filetype plugin indent on
    syntax enable
    filetype detect
  endif
endfunction

function! vimrc#windowjump(i) abort
  let cur_winid = win_getid()
  let cur_winnr = winnr()
  let pre_winnr = win_id2win(g:pre_winid)
  let max_winnr = winnr('$')
  if max_winnr >= a:i  " 合法性检查
    if cur_winnr == a:i  " 与i3 workspace跳转行为相同
      if pre_winnr != 0
        " 如果不是 command line window
        if getcmdwintype() == ''
          exe pre_winnr . 'wincmd w'
        endif
      else  " 两个窗口时来回切换
        if max_winnr == 2
          let n = 3 - a:i
          exe pre_winnr . 'wincmd w'
        endif
      endif
    else
      if getcmdwintype() == ''
        exe a:i . 'wincmd w'
      endif
    endif
  endif
endfunction

" let last_winnr = winnr('#')

function! vimrc#cdNode(context) abort
    let [curdir] = a:context.targets
    :py3 << EOF
import vim
from pathlib import Path
str = vim.eval('curdir')
path = Path(str)
if not path.is_dir():
  path = Path(str).parent
print(path)
vim.command(f"let dir='{path}'")
EOF
    exe 'cd ' . dir
endfunction


let defaults = {'placeholder': '...', 'line': 'L', 'multiplication': '*' }
let g:FoldText_placeholder    = get(g:, 'FoldText_placeholder',    defaults['placeholder'])
let g:FoldText_line           = get(g:, 'FoldText_line',           defaults['line'])
let g:FoldText_multiplication = get(g:, 'FoldText_multiplication', defaults['multiplication'])
let g:FoldText_gap            = get(g:, 'FoldText_gap',            4)
let g:FoldText_info           = get(g:, 'FoldText_info',           1)
unlet defaults

" function! MyFoldText()
"   let line = v:foldstart
"   let line .= " + "
"   let end = v:foldend - v:foldstart
"   let line .= end
"   let line .= " "
"   let line .= getline(v:foldstart)
"   let sub = substitute(line, '/\*\|\*/\|{{{\d\=', '', 'g')
"   return v:folddashes.sub
" endfunction
function! vimrc#FoldText()
  let fs = v:foldstart
  " TODO v:foldstart可能是空行吗
  " while getline(fs) =~ '^\s*$'
  "   let fs = nextnonblank(fs + 1)
  " endwhile
  if fs > v:foldend
    let line = getline(v:foldstart)
  else
    let spaces = repeat(' ', &tabstop)
    let line = substitute(getline(fs), '\t', spaces, 'g')
  endif

  let endBlockChars   = ['end', '}', ']', ')', '})', '},', '}}}']
  let endBlockRegex = printf('^\(\s*\|\s*\"\s*\)\(%s\);\?$', join(endBlockChars, '\|'))
  let endCommentRegex = '\s*\*/$'
  let startCommentBlankRegex = '\v^\s*/\*!?\s*$'

  let foldEnding = strpart(getline(v:foldend), indent(v:foldend), 3)

  if foldEnding =~ endBlockRegex
    if foldEnding =~ '^\s*\"'
      let foldEnding = strpart(getline(v:foldend), indent(v:foldend)+2, 3)
    end
    let foldEnding = " " . g:FoldText_placeholder . " " . foldEnding
  elseif foldEnding =~ endCommentRegex
    if getline(v:foldstart) =~ startCommentBlankRegex
      let nextLine = substitute(getline(v:foldstart + 1), '\v\s*\*', '', '')
      let line = line . nextLine
    endif
    let foldEnding = " " . g:FoldText_placeholder . " " . foldEnding
  else
    let foldEnding = " " . g:FoldText_placeholder
  endif

  let foldColumnWidth = (&foldcolumn ? &foldcolumn : 0) + (get(g:, 'gitgutter_enabled', 0) ? 3 : 0)
  let numberColumnWidth = &number ? strwidth(line('$')) : 0
  let width = winwidth(0) - foldColumnWidth - numberColumnWidth

  let ending = ""
  if g:FoldText_info
    let foldSize = 1 + v:foldend - v:foldstart
    let ending = printf("%s%s", g:FoldText_multiplication, foldSize)
    let ending = printf("%s%-6s", g:FoldText_line, ending)

    if strwidth(line . foldEnding . ending) >= width
      let line = strpart(line, 0, width - strwidth(foldEnding . ending))
    endif
  endif

  let expansionStr = repeat(" ", width - g:FoldText_gap - strwidth(line . foldEnding . ending))
  return line . foldEnding . expansionStr . ending
endfunction

function! vimrc#open_default_shell() abort
  exe 'topleft split'
  let lines = &lines * 28 / 100
  if lines < winheight(0)
    exe 'resize ' . lines
  endif
  if g:Windows
    let shell = empty($SHELL) ? 'powershell.exe' : $SHELL
  else
    let shell = empty($SHELL) ? 'zsh' : $SHELL
  endif
  if has('nvim')
    exe 'terminal '.shell
    " setlocal nonumber norelativenumber
    " setlocal statusline=%{b:term_title}
  else
    call term_start(shell, {'curwin' : 1, 'term_finish' : 'close'})
  endif
  setlocal nobuflisted
  startinsert
endfunction
